Skip to content

feat: Squad 2.0 decoupled backend and multi-host client adapters (Claude, Kiro, OpenCode, Cursor, Codex, Antigravity) - #2239

Closed
tamirdresher wants to merge 51 commits into
devfrom
squad/2.0-preview
Closed

tamirdresher wants to merge 51 commits into
devfrom
squad/2.0-preview

Conversation

@tamirdresher

Copy link
Copy Markdown
Collaborator

Supersedes #2238 (same work, moved to an in-repo branch squad/2.0-preview so reviewers and early testers can fetch it directly from this repo; Copilot's 19 review comments on #2238 are all addressed in this branch).

Squad 2.0: decoupled backend + multi-host client adapters

Squad can now run natively in Claude Code, Kiro, OpenCode, Cursor, OpenAI Codex and Google Antigravity (plus Copilot), with the host client decoupled from the state/backend. Hosts own native bootstrap/projection and capability declaration; conversation semantics, routing, durable state and authorization stay in the shared backend contract. MCP (squad_state) is a local tool transport bridge behind that contract, not the wire contract.

This branch is the integrated Squad 2.0 line (over dev), so it carries the earlier backend/spec work as well as the client adapters.

Reviewer map (suggested order: spec → interfaces → backend → projections → CLI → tests → docs)

  1. Spec (what must hold): docs/specification/client-backend-decoupling-v0.2.md, docs/specification/client-harness-adapters-v0.2.md, docs/specification/adr-001-client-control-execution-boundary.md, normative fixtures test-fixtures/spec/suite-v0.2/capability-matrix.json and test-fixtures/spec/suite-v0.2/golden-trace.json.
  2. Interfaces (the contracts): packages/squad-sdk/src/backend/types.ts (SquadBackend, envelope/cursor/error/capability types, HarnessAdapter SPI) and packages/squad-sdk/src/client/adapter-contract.ts (ClientAdapter facade, AdapterUnboundError, createClientAdapter).
  3. Backend: packages/squad-sdk/src/backend/local-backend.ts, durable-http-backend.ts, harness-registry.ts, index.ts (createSquadBackend); the MCP transport adapter packages/squad-cli/src/cli/core/backend-mcp.ts wired through packages/squad-cli/src/cli/commands/state-mcp.ts.
  4. Projections (per-host files and config merges): packages/squad-sdk/src/client/adapters/{types,adapters,capabilities,apply,portable,coordinator}.ts; casting-registry repair/backfill in packages/squad-sdk/src/casting/handwritten-registry.ts.
  5. CLI: packages/squad-cli/src/cli/core/clients.ts, init.ts, upgrade.ts, packages/squad-cli/src/cli-entry.ts, packages/squad-cli/src/cli/commands/cast.ts.
  6. Tests: test/specification-suite.test.ts, test/backend.test.ts, test/clients.test.ts, test/clients-real-cli.test.ts, test/squad-20-security-contracts.test.ts, test/squad-20-all-scenarios.e2e.test.ts, test/squad-20-real-clients-stdio.e2e.test.ts, test/docs-build.test.ts, test/cli-command-wiring.test.ts.
  7. Docs: docs/SQUAD-2.0-OVERVIEW.md, docs/tutorials/multi-client-quickstart.md, docs/tutorials/durable-backend-and-custom-harness.md, docs/src/content/docs/concepts/squad-2-0-architecture.md, docs/src/content/docs/scenarios/using-squad-across-clients.md, docs/proposals/squad-2.0-security-and-isolation.md.

What's in it

  • Backend and security (packages/squad-sdk/src/backend/): decoupled backend, harness SPI, MCP bridge, security/conformance contracts, RC1-to-stable exit-criteria tests.
  • Client adapters (packages/squad-sdk/src/client/):
    • HostProjection: pure workspace projection for copilot, claude, kiro, opencode, cursor, codex, antigravity (no runtime dependency).
    • ClientAdapter (adapter-contract.ts): thin spec-compliant facade (describe, projectWorkspace, getCapabilities; submit/subscribe/cancel/respondApproval delegate to a bound runtime, otherwise AdapterUnboundError).
    • Canonical string[] capability tokens are authoritative; boolean ClientCapabilities flags are a derived view (conflicts throw). Advertised vs negotiated (effectiveCapabilities = client ∩ backend ∩ policy) kept separate.
    • Deprecated @bradygaster/squad-sdk/clients re-exports the same symbols.
    • Host-agnostic coordinator core prompt plus per-host dispatch section; JSON/TOML config merges only touch Squad's own keys, so user settings in .mcp.json, .kiro/settings/mcp.json, opencode.json, .cursor/mcp.json, .codex/config.toml survive squad upgrade.
  • CLI: squad init --client <list|all> and squad upgrade --client, persisted in .squad/config.json clients[] (portable ids only; credentials/paths rejected). Hosts use only the coordinator file plus .squad/agents/<name>/charter.md (no per-member subagent files).
  • Docs/spec: docs/specification/*, docs/SQUAD-2.0-OVERVIEW.md, multi-client tutorials.

Verification

  • All 9 suites pass: 488 passed, 0 failed (npx vitest run over test/cli-command-wiring.test.ts, test/specification-suite.test.ts, test/backend.test.ts, test/clients.test.ts, test/clients-real-cli.test.ts, test/squad-20-security-contracts.test.ts, test/squad-20-all-scenarios.e2e.test.ts (126 tests), test/squad-20-real-clients-stdio.e2e.test.ts, test/docs-build.test.ts; 17 conditional skips).
  • test/clients-real-cli.test.ts runs the real claude, opencode, kiro, codex, agy and cursor-agent binaries against the generated config (run it alone if the machine is under load); squad-20-real-clients-stdio.e2e spawns the real state-mcp over stdio from each host's generated config.
  • Live interactive sessions (cli-tunnel, fresh repo, init -> cast -> parallel build -> tests): Claude (also issues + "Ralph, go" until PRs merged, 34/34), opencode (reviewer rejection, lockout, revision, approval, 24/24; fresh-session recovery + Scribe merge), Codex (10/10; fresh-session recovery + Scribe merge), Antigravity (casting verified; build hit a per-model quota), Cursor (cast, build 16/16, issues filed; Ralph blocked by the free-plan usage limit). Kiro: config loading and agent discovery verified; no live model run (free-tier monthly limit).
  • Non-normative live-demo evidence (sanitized off the PR branch): screenshots and raw PTY transcripts are not part of this PR or of any public branch because they contain local paths. They live in a separate private repo, https://github.com/tamirdresher/squad-2-0-demos (available to reviewers on request).
  • All demo runs used permissive/bypass permissions: controlled integration demos, not the production security model.

Known issues / caveats

  • Update: test/cli-command-wiring.test.ts is fixed: the internal backend-mcp helper moved from commands/ to cli/core/backend-mcp.ts (it is imported by state-mcp, not a CLI command). The spec deltas (7 hosts, HostProjection, capability tokens) are now in client-harness-adapters-v0.2.md and suite-v0.2/capability-matrix.json.
  • This branch also adds casting-registry repair/backfill for LLM-handwritten registries (casting/handwritten-registry.ts), non-TTY-safe squad init prompts, and .gitignore entries for .claude/worktrees/ and NUL.
  • The full repo suite also shows pre-existing timeouts/failures unrelated to clients (gh-aw, state-backend, OTel).
  • npm run build reports pre-existing @github/copilot-sdk typing errors in src/adapter/client.ts; tsc still emits.
  • An old published squad (0.13.x) on PATH has a stub cast --name; the local build must come first on PATH. squad init links repos to a personal squad when one exists (existing behaviour; set SQUAD_NO_PERSONAL=1 for clean demos).
  • Not demonstrated: Kiro/Cursor live runs, restart recovery on Antigravity, non-bypass permission mode.

Copilot and others added 30 commits October 17, 2026 22:15
Add SquadBackend contract with versioned envelope protocol, local and durable-http backends, harness registry, capability negotiation, versioned approvals, cancel-by-runId, and squad_backend_* MCP transport adapter.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Add security/isolation proposal and executable contract suite covering path/MCP/epoch guards, configured-vs-negotiated capabilities, versioned approvals with runId cancellation, loss-tolerant projection, and the golden cross-adapter conformance trace. Include packages/squad-sdk tests in vitest config.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Add ClientAdapter/ProjectionFile architecture in squad-sdk (copilot, claude,
kiro, opencode, cursor) with host-agnostic coordinator core, per-host dispatch
sections, declared ClientCapabilities, resolveEffectiveCapabilities, and
portable clients[] sanitization. Non-clobbering JSON/marker-block merging.

CLI: --client <list|all> on init and upgrade, persisted to .squad/config.json
clients[]; upgrade refreshes configured clients. Tests in test/clients.test.ts.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Bring Brady's specification suite updates into the Squad 2.0 worktree, add the new v0.2 client/backend and client/harness protocol specs, and freeze the rc1 protocol baseline with ADR and immutable fixtures.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…store clobbered spec docs

Backend capabilities now use the v0.2 capability-matrix vocabulary; lastAcceptedSeq is the last accepted event sequence; conversation.created no longer leaks the lease epoch; MCP send_message accepts typed parts without content. Restore Charter/Core/Ceremony/Governance/Interop/README/inventory docs that the spec branch regressed to older revisions, keeping only the v0.2 profile additions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…ebase

Covers client projections, capability intersection vs capability-matrix.json, LocalSquadBackend across 5 harnesses, DurableHttpSquadBackend against a mock DurableSquad, the MCP bridge on local and durable-http, and the normative golden trace.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Closes #2069

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…tion, clean-room)

Add uninstallClients/removeProjection for clean rollback of client projections, make harness event delivery idempotent (duplicate/out-of-order), and rehydrate harness subscriptions for in-flight turns after a broker restart. New e2e tests cover v0.1 upgrade+rollback, partial/duplicate/shuffled delivery and restart with an approval in flight, and a clean-room client+harness checked against golden-trace.json and capability-matrix.json.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Project claude/opencode/kiro configs, parse them from disk, spawn state-mcp as a real child process over stdio JSON-RPC and exercise squad_state_* and all squad_backend_* tools including process restart and resume. Smoke-test installed claude/opencode/kiro binaries against the workspaces when present on PATH.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…I tests

Real Kiro CLI resolves agent `resources` file:// paths against the workspace
root (only `prompt` is relative to the agent config), so use
file://.squad/team.md rather than ../../. Skip the Coordinator row when
projecting Claude member subagents (it produced a bogus squad-squad agent).
Add real-binary tests (claude, opencode, kiro-cli) that skip when absent.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…I tests

Real Kiro CLI resolves agent `resources` file:// paths against the workspace
root (only `prompt` is relative to the agent config), so use
file://.squad/team.md rather than ../../. Skip the Coordinator row when
projecting Claude member subagents (it produced a bogus squad-squad agent).
Add real-binary tests (claude, opencode, kiro-cli) that skip when absent.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Codex: AGENTS.md managed block (id-scoped), .codex/config.toml
[mcp_servers.squad_state] via a non-destructive TOML table merge (startup
timeout defaulted to 60s for cold npx), .codex/agents/squad-<member>.toml.
Antigravity: .agents/agents/squad.md (+ member subagents, mcpServers
frontmatter) and a GEMINI.md block. Block markers can carry an id so several
clients share one file. Real-binary tests for codex and agy; verified against
codex-cli 0.163 and agy 1.4.0.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…le state

Found with real models: opencode's Glob skipped .squad/ so the coordinator concluded no team existed and re-cast it over the real team; models also tried squad_state_write for team.md/routing.md/charters, which the state tools reject. Add a guarded Init Mode that decides via squad_state_read, never re-casts an existing team, and document static config as ordinary files.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…tigravity to capability matrix

Make removeProjection handle text (TOML) projections and block ids introduced with the codex/antigravity adapters, add both clients to the v0.2 capability matrix fixture, and generalize the all-scenarios projection assertions to every client.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…e in shared prompt

opencode now projects .opencode/agent/squad-<member>.md (mode: subagent); claude/opencode/codex/antigravity member agents accept an optional model from .squad/config.json clientModels (per client, per member slug, '*' wildcard; values validated). Shared coordinator prompt gains host-agnostic Ralph mode (coordinator-driven gh scan/route/PR loop).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…lot prompt

Shared prompt now carries Response Mode Selection, Scribe drop-box protocol, reviewer rejection + strict lockout, Rai traffic light, Fact Checker + devil's advocate, ceremonies, 5-root skill-aware routing, memory/state handshake, GitHub Issues + PRD mode, cross-squad delegation, human/@copilot members, anti-patterns, Ralph mode, and a guarded Init Mode (auto-confirm, no glob on .squad, scratch dir, cast via 'squad cast', never hand-edit the checksummed casting registry, stop after casting).

Verified live with Claude Code: headless 'proceed' now casts in one turn, Scribe merges the inbox; hand-written casting registry broke 'squad upgrade', hence the cast-CLI rule.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…y image name

Found in live Claude demos: Ralph ran taskkill /IM node.exe (killed its own proxy) and Claude left embedded worktree repos that broke git add.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
- squad cast --sync registers hand-written team.md members in the checksummed casting registry (idempotent); prompt uses it when 'cast --name' is unavailable (old npx-cached squad).
- Antigravity agents declare tools (omitted list = none: agent had no shell, Ralph could not use gh).
- Member slugs normalize diacritics consistently in adapters and cast.

Found in live Kiro/Antigravity/interactive-Claude (cli-tunnel) runs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…idence, claude --mcp-config note

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…s, explicit fallback

From reviewer feedback on live runs: model asked for squad_state_read but hosts expose prefixed names; directory keys read as files (EISDIR); Scribe/Ralph/Rai/Fact Checker subagents missing when team.md was rewritten; silent owner substitution.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…shed via claude-sonnet-4-6 model, per-model quota)

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Default is now a single coordinator file per host, like Copilot. Member
subagent files are projected only with --member-agents, config.json
memberAgents: true, or when clientModels is configured.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

🔴 Impact Analysis — PR #2239

Risk tier: 🔴 CRITICAL

📊 Summary

Metric Count
Files changed 58
Files added 36
Files modified 22
Files deleted 0
Modules touched 5
Critical files 7

🎯 Risk Factors

  • 58 files changed (>50 → CRITICAL)
  • 5 modules touched (5-8 → HIGH)
  • Critical files touched: packages/squad-sdk/package.json, packages/squad-sdk/src/backend/index.ts, packages/squad-sdk/src/casting/index.ts, packages/squad-sdk/src/client/adapters/index.ts, packages/squad-sdk/src/client/index.ts, packages/squad-sdk/src/clients/index.ts, packages/squad-sdk/src/index.ts

📦 Modules Affected

docs (15 files)
  • docs/SQUAD-2.0-OVERVIEW.md
  • docs/proposals/squad-2.0-security-and-isolation.md
  • docs/specification/README.md
  • docs/specification/adr-001-client-control-execution-boundary.md
  • docs/specification/client-backend-decoupling-v0.2.md
  • docs/specification/client-harness-adapters-v0.2.md
  • docs/src/content/docs/concepts/squad-2-0-architecture.md
  • docs/src/content/docs/reference/cli.md
  • docs/src/content/docs/reference/config.md
  • docs/src/content/docs/reference/sdk.md
  • docs/src/content/docs/scenarios/client-compatibility.md
  • docs/src/content/docs/scenarios/using-squad-across-clients.md
  • docs/src/navigation.ts
  • docs/tutorials/durable-backend-and-custom-harness.md
  • docs/tutorials/multi-client-quickstart.md
root (7 files)
  • .changeset/squad-2-0-multi-host-clients.md
  • CONTRIBUTING.md
  • README.md
  • cspell.json
  • test-fixtures/spec/suite-v0.1/index.json
  • test-fixtures/spec/suite-v0.2/capability-matrix.json
  • test-fixtures/spec/suite-v0.2/golden-trace.json
squad-cli (7 files)
  • packages/squad-cli/src/cli-entry.ts
  • packages/squad-cli/src/cli/commands/state-mcp.ts
  • packages/squad-cli/src/cli/core/backend-mcp.ts
  • packages/squad-cli/src/cli/core/clients.ts
  • packages/squad-cli/src/cli/core/command-help.ts
  • packages/squad-cli/src/cli/core/init.ts
  • packages/squad-cli/src/cli/core/upgrade.ts
squad-sdk (21 files)
  • packages/squad-sdk/package.json
  • packages/squad-sdk/src/backend/durable-http-backend.ts
  • packages/squad-sdk/src/backend/harness-registry.ts
  • packages/squad-sdk/src/backend/index.ts
  • packages/squad-sdk/src/backend/local-backend.ts
  • packages/squad-sdk/src/backend/state-backend-store.ts
  • packages/squad-sdk/src/backend/types.ts
  • packages/squad-sdk/src/casting/handwritten-registry.ts
  • packages/squad-sdk/src/casting/index.ts
  • packages/squad-sdk/src/client/adapter-contract.ts
  • packages/squad-sdk/src/client/adapters/adapters.ts
  • packages/squad-sdk/src/client/adapters/apply.ts
  • packages/squad-sdk/src/client/adapters/capabilities.ts
  • packages/squad-sdk/src/client/adapters/coordinator.ts
  • packages/squad-sdk/src/client/adapters/index.ts
  • packages/squad-sdk/src/client/adapters/portable.ts
  • packages/squad-sdk/src/client/adapters/types.ts
  • packages/squad-sdk/src/client/index.ts
  • packages/squad-sdk/src/clients/index.ts
  • packages/squad-sdk/src/config/init.ts
  • packages/squad-sdk/src/index.ts
tests (8 files)
  • test/backend.test.ts
  • test/clients-real-cli.test.ts
  • test/clients.test.ts
  • test/docs-build.test.ts
  • test/specification-suite.test.ts
  • test/squad-20-all-scenarios.e2e.test.ts
  • test/squad-20-real-clients-stdio.e2e.test.ts
  • test/squad-20-security-contracts.test.ts

⚠️ Critical Files

  • packages/squad-sdk/package.json
  • packages/squad-sdk/src/backend/index.ts
  • packages/squad-sdk/src/casting/index.ts
  • packages/squad-sdk/src/client/adapters/index.ts
  • packages/squad-sdk/src/client/index.ts
  • packages/squad-sdk/src/clients/index.ts
  • packages/squad-sdk/src/index.ts

This report is generated automatically for every PR. See #733 for details.

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

🏗️ Architectural Review

Authoritative evidence: base-controlled pull_request_target reporter.

⚠️ Architectural review: 3 warning(s).

Severity Category Finding Files
🟡 warning bootstrap-area 5 file(s) in the bootstrap area (packages/squad-cli/src/cli/core/) were modified. These files must maintain zero external dependencies. Review carefully. packages/squad-cli/src/cli/core/backend-mcp.ts, packages/squad-cli/src/cli/core/clients.ts, packages/squad-cli/src/cli/core/command-help.ts, packages/squad-cli/src/cli/core/init.ts, packages/squad-cli/src/cli/core/upgrade.ts
🟡 warning export-surface Package entry point(s) modified with 186 new/changed export(s). New public API surface requires careful review for backward compatibility. packages/squad-sdk/src/index.ts
🟡 warning sweeping-refactor This PR touches 58 files (58 modified/added, 0 deleted). Large PRs are harder to review — consider splitting if possible. —

Automated architectural review — informational only.

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 24d6670

PR Scope: 📦🔧 Mixed (product + infrastructure)

⚠️ 2 item(s) to address before review

Status Check Details
❌ Single commit 51 commits — consider squashing before review
✅ Not in draft Ready for review
✅ Branch up to date Up to date with dev
❌ Copilot review No Copilot review yet — it may still be processing
✅ Changeset present Changeset file found
✅ Scope clean ⚠️ PR includes 1 docs/proposals/ file(s) — ensure these are intentional
✅ No merge conflicts No merge conflicts
✅ Copilot threads resolved 3 active Copilot thread(s) resolved (6 outdated skipped)
✅ CI passing All checks passing

Files Changed (58 files, +11771 −15)

File +/−
.changeset/squad-2-0-multi-host-clients.md +6 −0
CONTRIBUTING.md +11 −0
README.md +13 −2
cspell.json +3 −0
docs/SQUAD-2.0-OVERVIEW.md +333 −0
docs/proposals/squad-2.0-security-and-isolation.md +103 −0
docs/specification/README.md +6 −0
docs/specification/adr-001-client-control-execution-boundary.md +59 −0
docs/specification/client-backend-decoupling-v0.2.md +487 −0
docs/specification/client-harness-adapters-v0.2.md +481 −0
docs/src/content/docs/concepts/squad-2-0-architecture.md +145 −0
docs/src/content/docs/reference/cli.md +2 −0
docs/src/content/docs/reference/config.md +2 −0
docs/src/content/docs/reference/sdk.md +9 −0
docs/src/content/docs/scenarios/client-compatibility.md +2 −0
docs/src/content/docs/scenarios/using-squad-across-clients.md +127 −0
docs/src/navigation.ts +2 −0
docs/tutorials/durable-backend-and-custom-harness.md +390 −0
docs/tutorials/multi-client-quickstart.md +361 −0
packages/squad-cli/src/cli-entry.ts +22 −2
packages/squad-cli/src/cli/commands/state-mcp.ts +20 −5
packages/squad-cli/src/cli/core/backend-mcp.ts +209 −0
packages/squad-cli/src/cli/core/clients.ts +102 −0
packages/squad-cli/src/cli/core/command-help.ts +2 −0
packages/squad-cli/src/cli/core/init.ts +30 −2
packages/squad-cli/src/cli/core/upgrade.ts +57 −2
packages/squad-sdk/package.json +8 −0
packages/squad-sdk/src/backend/durable-http-backend.ts +232 −0
packages/squad-sdk/src/backend/harness-registry.ts +47 −0
packages/squad-sdk/src/backend/index.ts +29 −0
packages/squad-sdk/src/backend/local-backend.ts +784 −0
packages/squad-sdk/src/backend/state-backend-store.ts +26 −0
packages/squad-sdk/src/backend/types.ts +417 −0
packages/squad-sdk/src/casting/handwritten-registry.ts +308 −0
packages/squad-sdk/src/casting/index.ts +10 −0
packages/squad-sdk/src/client/adapter-contract.ts +201 −0
packages/squad-sdk/src/client/adapters/adapters.ts +334 −0
packages/squad-sdk/src/client/adapters/apply.ts +379 −0
packages/squad-sdk/src/client/adapters/capabilities.ts +140 −0
packages/squad-sdk/src/client/adapters/coordinator.ts +108 −0
packages/squad-sdk/src/client/adapters/index.ts +6 −0
packages/squad-sdk/src/client/adapters/portable.ts +49 −0
packages/squad-sdk/src/client/adapters/types.ts +82 −0
packages/squad-sdk/src/client/index.ts +5 −0
packages/squad-sdk/src/clients/index.ts +9 −0
packages/squad-sdk/src/config/init.ts +4 −1
packages/squad-sdk/src/index.ts +3 −0
test-fixtures/spec/suite-v0.1/index.json +38 −0
test-fixtures/spec/suite-v0.2/capability-matrix.json +155 −0
test-fixtures/spec/suite-v0.2/golden-trace.json +63 −0
... +8 more files

Total: +11771 −15


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved configuration data loss, casting integrity, containment, and backend integration issues block approval.

9 open issues
What changed in this PR

Introduces Squad 2.0’s shared backend contract and host adapters, allowing one team to work across seven AI clients.

Changes:

  • Adds backend interfaces, HTTP transport, harness registration, and MCP integration.
  • Adds host projections, capability declarations, and persistent --client configuration.
  • Expands specifications, fixtures, integration checks, and documentation.
File Description
vitest.config.ts Resolves SDK source and includes SDK tests.
test/​specification-suite.test.ts Registers new requirements documents.
test/​docs-build.test.ts Checks new documentation pages.
test/​clients-real-cli.test.ts Adds host-binary integration checks.
test-fixtures/​spec/​suite-v0.2/​golden-trace.json Defines recovery and cancellation baseline.
test-fixtures/​spec/​suite-v0.2/​capability-matrix.json Defines host capability baseline.
test-fixtures/​spec/​suite-v0.1/​index.json Registers decoupling requirements.
README.md Introduces multi-host commands.
packages/​squad-sdk/​src/​index.ts Exports backend APIs.
packages/​squad-sdk/​src/​config/​init.ts Adds runtime ignore entries.
packages/​squad-sdk/​src/​clients/​index.ts Provides compatibility re-exports.
packages/​squad-sdk/​src/​client/​index.ts Exports client adapter APIs.
packages/​squad-sdk/​src/​client/​adapters/​types.ts Defines host projection types.
packages/​squad-sdk/​src/​client/​adapters/​portable.ts Normalizes persisted client IDs.
packages/​squad-sdk/​src/​client/​adapters/​index.ts Exports projection modules.
packages/​squad-sdk/​src/​client/​adapters/​coordinator.ts Defines coordinator and dispatch instructions.
packages/​squad-sdk/​src/​client/​adapters/​capabilities.ts Declares and intersects capabilities.
packages/​squad-sdk/​src/​client/​adapters/​apply.ts Applies and removes projections.
packages/​squad-sdk/​src/​client/​adapters/​adapters.ts Implements seven host projections.
packages/​squad-sdk/​src/​client/​adapter-contract.ts Adds runtime-bound client facade.
packages/​squad-sdk/​src/​casting/​index.ts Exports registry repair helpers.
packages/​squad-sdk/​src/​casting/​handwritten-registry.ts Adds registry repair and backfill.
packages/​squad-sdk/​src/​backend/​types.ts Defines backend and harness contracts.
packages/​squad-sdk/​src/​backend/​index.ts Adds backend factory and exports.
packages/​squad-sdk/​src/​backend/​harness-registry.ts Registers harnesses and validates extensions.
packages/​squad-sdk/​src/​backend/​durable-http-backend.ts Implements HTTP backend client.
packages/​squad-sdk/​package.json Exposes new package entrypoints.
packages/​squad-cli/​src/​cli/​core/​upgrade.ts Refreshes projections and casting state.
packages/​squad-cli/​src/​cli/​core/​init.ts Projects clients and guards interactive prompts.
packages/​squad-cli/​src/​cli/​core/​command-help.ts Documents client flags.
packages/​squad-cli/​src/​cli/​core/​clients.ts Persists and synchronizes client configuration.
packages/​squad-cli/​src/​cli/​core/​backend-mcp.ts Exposes backend operations as MCP tools.
packages/​squad-cli/​src/​cli/​commands/​state-mcp.ts Registers backend MCP tools.
packages/​squad-cli/​src/​cli-entry.ts Parses and forwards client flags.
docs/​tutorials/​multi-client-quickstart.md Provides host setup walkthroughs.
docs/​tutorials/​durable-backend-and-custom-harness.md Explains backend and harness integration.
docs/​src/​navigation.ts Links new documentation pages.
docs/​src/​content/​docs/​scenarios/​using-squad-across-clients.md Documents multi-host workflows.
docs/​src/​content/​docs/​scenarios/​client-compatibility.md Links multi-host guidance.
docs/​src/​content/​docs/​reference/​sdk.md Documents adapter APIs.
docs/​src/​content/​docs/​reference/​config.md Documents persisted client IDs.
docs/​src/​content/​docs/​reference/​cli.md Documents multi-host CLI usage.
docs/​src/​content/​docs/​concepts/​squad-2-0-architecture.md Explains architectural boundaries.
docs/​SQUAD-2.0-OVERVIEW.md Summarizes architecture and conformance goals.
docs/​specification/​README.md Registers new specification profiles.
docs/​specification/​client-backend-decoupling-v0.2.md Defines decoupling requirements.
docs/​specification/​adr-001-client-control-execution-boundary.md Records architectural decision.
docs/​proposals/​squad-2.0-security-and-isolation.md Defines proposed security gates.
cspell.json Adds domain vocabulary.
CONTRIBUTING.md Adds adapter contribution guidance.
.changeset/​squad-2-0-multi-host-clients.md Declares major SDK and CLI releases.

Review effort: Balanced

Copilot and others added 4 commits October 18, 2026 21:34
…-rejection audit, stable outbox operationId

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
CI: drop the root SDK source alias from vitest.config.ts (dual module instances), wrap --client help lines to <=80 cols.
Backend: normalize legacy outbox ids, recovery-mutex stale-lock handling, persisted admission cursor + payload conflict detection, keep deliveries when the harness is missing, no re-entrant load on synchronous replay, createMcpBackend honors the configured state backend, HTTP body reads retried.
Client/casting: TOML [[array_table]] boundaries and quoted keys, capability tokens 1:1 with capability-matrix.json, retired agents preserved and repairs committed through the canonical manifest writer.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…ox through before delivery, journey + repro tests

Restores .github/agents/squad.agent.md (a local test run had stamped it, failing template-sync in CI). Repairs a handwritten casting registry before the strict upgrade preflight and keeps config.json writes inside the squad dir.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…only when no cast history exists

A blanket pre-repair defeated the deliberate fail-closed refusals for registries with real history (test/cli/legacy-casting-upgrade).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
@tamirdresher

Copy link
Copy Markdown
Collaborator Author

Superseded by the 4-PR stack (Stack #2255) addressing all review recommendations and splitting the changes into smaller, focused layers:

  1. Layer 1 (dev ← --client adapters): feat(clients): add --client host adapters for Claude, Kiro, OpenCode, Cursor, Codex, and Antigravity [1/4] #2251 — feat(clients): add --client host adapters for Claude, Kiro, OpenCode, Cursor, Codex, and Antigravity [1/4]
  2. Layer 2 (Casting repair): fix(casting): repair handwritten casting registries under lock with dry-run support [2/4] #2252 — fix(casting): repair handwritten casting registries under lock with dry-run support [2/4]
  3. Layer 3 (Experimental /backend contract): feat(backend): add experimental /backend conversation and harness contract [3/4] #2253 — feat(backend): add experimental /backend conversation and harness contract [3/4]
  4. Layer 4 (Consolidated docs & spec): docs: consolidate Squad 2.0 multi-client and experimental backend documentation [4/4] #2254 — docs: consolidate Squad 2.0 multi-client and experimental backend documentation [4/4]

tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
… repair

- Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key
- Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting
- Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key
- Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair
- Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives

Refs #2239
Refs #2252

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
- Auto-select a single registered in-process harness in `squad_backend_send_message` when `harness` is omitted, and reject an omitted `harness` when multiple harnesses are registered instead of silently queueing; keep remote routing separate
- Default an omitted `limit` in `squad_backend_read_events` to `MAX_READ_EVENTS_LIMIT` (500)
- Read the response body outside the JSON parse `try/catch` in `DurableHttpSquadBackend.probe` so body timeouts and stream errors fail health checks
- Coordinate in-flight `adapter.submit` dispatches by `(conversationId, runId, seq)` and pass a deterministic `operationId` (`${conversationId}:${runId}:${seq}`) for crash-retry deduplication
- Remove queued approval deliveries for a turn when committing cancellation (`markCancelled` / terminal state) so `flushDeliveries` never retries or blocks on an obsolete approval
- Thread the publishing `harnessId` through `ensureSubscribed`, `applyEvent`, and `applyEventLocked` (including synchronous subscription replay) and verify it matches the turn's routed harness
- Reject a second distinct `approval-requested` event while a turn already has a `pendingApproval`
- Derive `createStateBackendStore` lock identity from the canonical shared storage (`.git` common dir across linked worktrees, resolved via `realpathSync.native`) and the state ref (`refs/heads/<branch>` or `refs/notes/<ref>`), unwrapping `TwoLayerBackend`
- Clear ambient `SQUAD_BACKEND_URL`, `SQUAD_BACKEND_TOKEN`, and `SQUAD_EXPERIMENTAL_BACKEND` before applying explicit test environment values in `McpStdioClient`

Refs #2239, #2253

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639
tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
…ions (Layer 1)

Carves Layer 1 of #2239 targeting dev and applies all Layer 1 review fixes:
- Isolate host coordinator projections so non-Squad sessions are not hijacked:
  - Codex writes full coordinator prompt to .codex/agents/squad.md and only a short discovery pointer block in AGENTS.md
  - Kiro sets .kiro/steering/squad.md to inclusion: manual (loaded by .kiro/agents/squad.json)
  - Cursor sets .cursor/rules/squad.mdc to alwaysApply: false
- Make multi-client projection strictly opt-in (no default .claude/worktrees/ or NUL in .gitignore on plain init/upgrade)
- Synchronize coordinator.ts with .github/agents/squad.agent.md as the canonical coordinator source of truth
- Throw on unclosed or inverted Squad managed block markers in upsertBlock/removeBlock
- Normalize inline and dotted squad_state TOML definitions in upsertTomlTable/removeTomlTable without duplicates
- Import from @bradygaster/squad-sdk/client, merge repeated --client flags, preserve unknown portable client IDs in config.json with a warning, and reject symlinked .squad directories

Refs #2239

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e
tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
…m team.md (Layer 2)

Carves Layer 2 of #2239 targeting tamirdresher-microsoft-stack-1-client-adapters and applies all Layer 2 review fixes:
- Acquire the casting writer lock (with symlink/lstat guards) BEFORE reading registry.json, history.json, or registry-history.commit.json in repairHandwrittenCastingRegistry and backfillCastingRegistryFromTeam
- Do not leave *.handwritten.bak clutter in .squad/casting/ by default (only when options.keepBackup === true is explicitly passed)
- Restore the exact in-memory pre-repair snapshot to disk and rethrow if commitCastingRegistryPair fails (never fall back to writing a fresh cast or deleting registry-history.commit.json)
- Never touch or rewrite valid canonical registries or registries with existing cast history
- Validate handwritten registry repair in memory during `squad upgrade --dry-run` so dry-run previews succeed without mutating disk while still failing closed on corrupt/unrepairable registries
- Guard interactive prompts in `squad init` via `isInteractiveSession()`

Refs #2239

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
… repair

- Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key
- Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting
- Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key
- Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair
- Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives

Refs #2239
Refs #2252

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
…tract (Layer 3)

Carves Layer 3 of #2239 targeting tamirdresher-microsoft-stack-2-casting-repair and applies all Layer 3 review fixes:
- Export the experimental conversation & harness contract from `@bradygaster/squad-sdk/backend` only (`BACKEND_CONTRACT_STAGE = 'experimental'`) without re-exporting from the root `@bradygaster/squad-sdk` barrel
- Gate `squad_backend_*` MCP tools in `squad state-mcp` behind explicit opt-in (`--experimental-backend`, `SQUAD_EXPERIMENTAL_BACKEND=1`, or `SQUAD_BACKEND_URL`)
- Fix `createFileStateStore` lock contention `catch` block so persistent `EACCES`/`EPERM` errors respect `lockTimeoutMs` and sleep between polls instead of spinning forever, and reject symlinked `.squad` or store root directories via `lstatSync`
- Track pending harness submissions in `LocalSquadBackend.sendMessage` so a failed or interrupted `harness.submit` is recovered on a same-`(runId, seq)` retry and returns the original admission cursor
- Implement real cross-process `wx` file locking with stale-lock recovery and symlink guards in `createStateBackendStore`
- Add per-attempt `requestTimeoutMs` (default 15_000 ms) via `AbortSignal.timeout` in `DurableHttpSquadBackend`

Refs #2239

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639
tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
- Auto-select a single registered in-process harness in `squad_backend_send_message` when `harness` is omitted, and reject an omitted `harness` when multiple harnesses are registered instead of silently queueing; keep remote routing separate
- Default an omitted `limit` in `squad_backend_read_events` to `MAX_READ_EVENTS_LIMIT` (500)
- Read the response body outside the JSON parse `try/catch` in `DurableHttpSquadBackend.probe` so body timeouts and stream errors fail health checks
- Coordinate in-flight `adapter.submit` dispatches by `(conversationId, runId, seq)` and pass a deterministic `operationId` (`${conversationId}:${runId}:${seq}`) for crash-retry deduplication
- Remove queued approval deliveries for a turn when committing cancellation (`markCancelled` / terminal state) so `flushDeliveries` never retries or blocks on an obsolete approval
- Thread the publishing `harnessId` through `ensureSubscribed`, `applyEvent`, and `applyEventLocked` (including synchronous subscription replay) and verify it matches the turn's routed harness
- Reject a second distinct `approval-requested` event while a turn already has a `pendingApproval`
- Derive `createStateBackendStore` lock identity from the canonical shared storage (`.git` common dir across linked worktrees, resolved via `realpathSync.native`) and the state ref (`refs/heads/<branch>` or `refs/notes/<ref>`), unwrapping `TwoLayerBackend`
- Clear ambient `SQUAD_BACKEND_URL`, `SQUAD_BACKEND_TOKEN`, and `SQUAD_EXPERIMENTAL_BACKEND` before applying explicit test environment values in `McpStdioClient`

Refs #2239, #2253

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639
tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
…osts (Layer 4)

Split from #2239 (Layer 4 of 4):
- Canonicalize @bradygaster/squad-sdk/client across architecture, overview, quickstart, and SDK docs
- Add Experimental Preview / Bring Your Own Server callouts for @bradygaster/squad-sdk/backend and document opt-in --experimental-backend / SQUAD_EXPERIMENTAL_BACKEND=1 MCP tools
- Update all 5-host lists to all 7 hosts (copilot, claude, kiro, opencode, cursor, codex, antigravity) and align generated-file tables with Layer 1 projections
- Consolidate architecture and multi-client docs into published Astro pages and align v0.2 specs

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9
tamirdresher added a commit that referenced this pull request Oct 22, 2026
… Cursor, Codex, and Antigravity [1/4] (#2251)

* feat(client): add multi-host --client adapters and opt-in CLI projections (Layer 1)

Carves Layer 1 of #2239 targeting dev and applies all Layer 1 review fixes:
- Isolate host coordinator projections so non-Squad sessions are not hijacked:
  - Codex writes full coordinator prompt to .codex/agents/squad.md and only a short discovery pointer block in AGENTS.md
  - Kiro sets .kiro/steering/squad.md to inclusion: manual (loaded by .kiro/agents/squad.json)
  - Cursor sets .cursor/rules/squad.mdc to alwaysApply: false
- Make multi-client projection strictly opt-in (no default .claude/worktrees/ or NUL in .gitignore on plain init/upgrade)
- Synchronize coordinator.ts with .github/agents/squad.agent.md as the canonical coordinator source of truth
- Throw on unclosed or inverted Squad managed block markers in upsertBlock/removeBlock
- Normalize inline and dotted squad_state TOML definitions in upsertTomlTable/removeTomlTable without duplicates
- Import from @bradygaster/squad-sdk/client, merge repeated --client flags, preserve unknown portable client IDs in config.json with a warning, and reject symlinked .squad directories

Refs #2239

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e

* fix(client): audit fixes for --client adapters (Codex TOML agent, symlink root handling, EOL/indent-preserving merges)

- H1: Codex coordinator is now a TOML custom agent (.codex/agents/squad.toml with name/description/developer_instructions, escaped multi-line string); AGENTS.md pointer, ANCHORS, dispatch text and uninstall updated
- H2: resolveInsideRoot realpaths the root once and only lstats components below it, so junctioned/symlinked ancestors (OneDrive, ~/code -> /Volumes) work; syncClients returns early with no requested/configured clients before any filesystem checks
- M2: symlinked target files inside the root (AGENTS.md -> CLAUDE.md) are written through; symlinks escaping the root are still refused
- M1: new 'lines' projection kind for .gitignore (plain lines under a `# squad:<id>` comment, no HTML markers); uninstall removes only the lines Squad added
- M3: emitted content follows the existing file's dominant EOL (LF for new files) for blocks, lines, JSON, TOML and removals
- M4: JSON merges preserve indentation (tabs/N spaces) and trailing-newline; OpenCode targets opencode.jsonc when it is the only config and reports an error instead of clobbering JSONC with comments
- M5: only persist newly requested clients whose projection had no errors (configured ones stay); atomic temp+rename writes; `squad upgrade --dry-run --client` prints the clients it would project (syncClients dryRun option)
- M6: real-CLI tests gated behind SQUAD_REAL_CLI_TESTS=1, PATH-only binary discovery, no hardcoded paths, shell:false, cursor-agent check is read-only
- changeset wording updated; tests added/updated in test/clients.test.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841

* fix(client): resolve all 6 Copilot PR review threads on #2251

- apply.ts (Thread 1): preserve parsed TOML key segments across sectionHeader,
  tableHeaderKeys, findTable, stripConflictingDottedAndInline, and removeTomlTable
  so quoted-dot server names ([mcp_servers."squad_state.env"]) remain untouched
- apply.ts (Thread 2): track multiline basic (""") and literal (''') string
  boundaries in assignmentEnd and advance scanners across multiline assignments
  so embedded TOML examples in developer_instructions are never rewritten
- apply.ts (Thread 3): refuse to extend enclosing ancestor inline/scalar tables
  (e.g. mcp_servers = { other = ... }) or non-table squad_state assignments
- portable.ts (Thread 4): trim before sensitivity checks and redact bare
  credential prefixes (ghp_, github_pat_, sk-, glpat-, xox*, AKIA, JWT) so
  they never surface in unknown-ID warnings or persist in config.json
- adapters.ts & clients-real-cli.test.ts (Thread 5): project native Codex
  .codex/agents/squad.toml role and verify real-CLI role discovery + coordinator
  developer_instructions activation on spawn_agent
- clients.ts & clients.test.ts (Thread 6): document the default Copilot
  bootstrap exception (.github/agents/squad.agent.md + .mcp.json) and test
  both plain runInit and runUpgrade command pipelines directly

Refs #2251

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e

---------

Co-authored-by: Copilot <Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
tamirdresher added a commit that referenced this pull request Oct 22, 2026
…ry-run support [2/4] (#2252)

* feat(casting): repair handwritten casting registries and backfill from team.md (Layer 2)

Carves Layer 2 of #2239 targeting tamirdresher-microsoft-stack-1-client-adapters and applies all Layer 2 review fixes:
- Acquire the casting writer lock (with symlink/lstat guards) BEFORE reading registry.json, history.json, or registry-history.commit.json in repairHandwrittenCastingRegistry and backfillCastingRegistryFromTeam
- Do not leave *.handwritten.bak clutter in .squad/casting/ by default (only when options.keepBackup === true is explicitly passed)
- Restore the exact in-memory pre-repair snapshot to disk and rethrow if commitCastingRegistryPair fails (never fall back to writing a fresh cast or deleting registry-history.commit.json)
- Never touch or rewrite valid canonical registries or registries with existing cast history
- Validate handwritten registry repair in memory during `squad upgrade --dry-run` so dry-run previews succeed without mutating disk while still failing closed on corrupt/unrepairable registries
- Guard interactive prompts in `squad init` via `isInteractiveSession()`

Refs #2239

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776

* fix(casting): per-record handwritten registry repair, charter-derived backfill ids, roll-forward-safe rollback

- H3: normalize handwritten registries per record — records that already parse as valid provenance records are preserved verbatim (all fields, timestamps, per-record universe); only incomplete records get missing fields synthesized. Preserve and bump the registry revision instead of resetting it. Archive pre-repair originals under handwritten-archive-<sha256>/ by default (keepBackup: false opts out) and report backupPath.
- H4: backfillCastingRegistryFromTeam derives agent ids from the team.md Charter column (.squad/agents/<id>/charter.md) or a charter whose ## Identity name matches; rows with no provable folder fail the backfill closed with a dropped list. Fix the test that expected "b-elanna" for the belanna folder.
- M8: wrapper-less shapes only accept record values carrying name/persistent_name/display_name/role; bare-string values and non-agent metadata are reported instead of guessed. Non-Latin names, duplicate names and id collisions no longer drop silently — RepairResult.dropped is populated and the repair fails closed; squad upgrade prints the reason and each dropped entry.
- M7: commitPairWithRollback only restores the pre-repair snapshot when the commit failed before its journal became durable (never on CastingCommitInDoubtError or after a successful commit), restores via temp+fsync+rename, and attaches restore failures as cause. recoverCastingRegistryTransaction runs under the lock before the snapshot so pending journals roll forward first.
- M9: single exported hasExistingCastHistory (empty arrays/objects are not history) replaces the CLI copy; a history.json holding one Init Mode snapshot consistent with the handwritten registry is normalized instead of blocking the repair. squad upgrade --dry-run previews the team.md backfill.
- Low: strip UTF-8 BOM before JSON.parse; anchor the team.md universe regex to a line start / table cell and fail the backfill closed instead of inventing one; recommit of a manifest-mismatched pair bumps the revision and requires a readable history object.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841

* fix(casting): address PR #2252 review threads on handwritten registry repair

- Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key
- Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting
- Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key
- Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair
- Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives

Refs #2239
Refs #2252

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776

---------

Co-authored-by: Copilot <Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
tamirdresher added a commit that referenced this pull request Oct 22, 2026
…tract [3/4] (#2253)

* feat(backend): add experimental /backend conversation and harness contract (Layer 3)

Carves Layer 3 of #2239 targeting tamirdresher-microsoft-stack-2-casting-repair and applies all Layer 3 review fixes:
- Export the experimental conversation & harness contract from `@bradygaster/squad-sdk/backend` only (`BACKEND_CONTRACT_STAGE = 'experimental'`) without re-exporting from the root `@bradygaster/squad-sdk` barrel
- Gate `squad_backend_*` MCP tools in `squad state-mcp` behind explicit opt-in (`--experimental-backend`, `SQUAD_EXPERIMENTAL_BACKEND=1`, or `SQUAD_BACKEND_URL`)
- Fix `createFileStateStore` lock contention `catch` block so persistent `EACCES`/`EPERM` errors respect `lockTimeoutMs` and sleep between polls instead of spinning forever, and reject symlinked `.squad` or store root directories via `lstatSync`
- Track pending harness submissions in `LocalSquadBackend.sendMessage` so a failed or interrupted `harness.submit` is recovered on a same-`(runId, seq)` retry and returns the original admission cursor
- Implement real cross-process `wx` file locking with stale-lock recovery and symlink guards in `createStateBackendStore`
- Add per-attempt `requestTimeoutMs` (default 15_000 ms) via `AbortSignal.timeout` in `DurableHttpSquadBackend`

Refs #2239

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639

* fix(backend): align experimental backend docs with implementation; harden durable-http, locks and MCP opt-in

- H5: rewrite test/squad-20-security-contracts.test.ts to exercise product code
  (createFileStateStore/resolveInsideRoot guards, mergeMcpServer/installClients,
  LocalSquadBackend idempotency/epochs/approvals/cursors, backend-mcp, DurableHttp);
  delete self-referential reference guards; proposal no longer claims an
  "executable contract" or CI-blocking gates
- H6: proposal, ADR and spec now describe the shipped behavior: opaque
  harness-supplied approval hash echoed back, cooperative client-asserted
  epochs (explicitly not a security boundary), unsigned cursors; stronger
  properties moved to "Future work / not implemented"
- H7: replace spec TypeScript contracts with the real signatures from
  backend/types.ts (SquadBackend, HarnessAdapter, RunState, ...); golden-trace
  fixture uses real BackendEnvelope.type names and the e2e runner no longer
  needs a translation table
- M10: squad_backend_send_message returns BackendError 'unavailable' when no
  harness is registered instead of queueing forever; health/negotiate expose
  harnesses: [] and executionAvailable: false; tool descriptions and specs
  state the bridge is transcript/event-log only
- M11: git-ignore .squad/backend/ in the upgrade scaffold (no merge=union)
- M12: SQUAD_BACKEND_URL alone no longer enables the tools; DurableHttp
  validates baseUrl (https, or http to loopback), uses redirect: 'error'
- M13: health probes get AbortSignal.timeout; file-store lock acquisition is
  async (lockAsync) for backend methods; read() only treats ENOENT as missing;
  corrupt conversation JSON surfaces as BackendError with the path; temp file
  is fsync'd before rename; spec documents whole-file snapshot limitation
- M14: createStateBackendStore requires a deterministic lock root (no mkdtemp
  fallback) and no longer prunes lock directories after release
- Low: MCP arg validation (role/parts/protocols/limit cap 500), generic
  message for non-contract errors, Windows reserved device names rejected as
  conversation ids, misplaced comment fixed, real-binary tests gated behind
  SQUAD_REAL_CLI_TESTS=1, flaky opt-in test timeout raised

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841

* fix(stack): align e2e scenarios with audited adapter/casting behavior; keep configured state backend out of .squad/backend; fail-closed casting repair reports instead of crashing

- e2e expectation updates for the audited stack behavior: Codex agent is
  `.codex/agents/squad.toml`; `.gitignore` projections are `# squad:claude`
  plain lines (exact restoration on removal still asserted);
  `normalizeHandwrittenCastingRegistry` callers use the new
  `NormalizeHandwrittenResult` shape; repair archives originals under
  `handwritten-archive-<sha256>/` instead of `.handwritten.bak`; a
  manifest-only recommit bumps the revision by one and keeps agents/history;
  team.md backfill resolves ids from charter folders (`belanna`, not
  `b-elanna`) and `parseTeamRoster` members carry `charterId`; a roster with
  no provable agent folder fails closed with the dropped row named
- role-keyed fixture now uses object entries (`tester: { name }`) since bare
  strings are rejected by design; a dedicated case asserts the bare-string
  rejection reason
- createStateBackendStore: a configured non-local state backend (git-notes,
  orphan, or any backend without a `root`) no longer gets its lock root from
  the team `.squad` dir. Locks live in a deterministic machine-local
  directory derived from the backend identity (`cwd` or the new `lockAnchor`
  option); `createMcpBackend` passes `lockAnchor` instead of `squadDir`, so
  `.squad/backend/` is never created when a non-local backend is configured
- squad upgrade: when the handwritten-registry repair fails closed and the
  pair is not readable as a managed pair, `ensureCastingDefaults` and the
  pre-preflight repair in `runUpgrade` throw an actionable error (reason,
  dropped entries, how to fix) instead of the generic "exactly one
  authoritative file exists" / preflight error

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841

* docs(spec): align Codex anchor and Claude .gitignore lines with projection code

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841

* fix(upgrade): keep legacy casting preflight authoritative; enrich only its generic error with the handwritten-repair reason

The fail-closed handwritten-registry path pre-empted preflightCastingRegistryPair, so legacy`entries` registries (and --dry-run) got the new error instead of the legacy migration/refusal they had before.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841

* fix(backend): resolve all 9 PR #2253 Copilot review findings

- Auto-select a single registered in-process harness in `squad_backend_send_message` when `harness` is omitted, and reject an omitted `harness` when multiple harnesses are registered instead of silently queueing; keep remote routing separate
- Default an omitted `limit` in `squad_backend_read_events` to `MAX_READ_EVENTS_LIMIT` (500)
- Read the response body outside the JSON parse `try/catch` in `DurableHttpSquadBackend.probe` so body timeouts and stream errors fail health checks
- Coordinate in-flight `adapter.submit` dispatches by `(conversationId, runId, seq)` and pass a deterministic `operationId` (`${conversationId}:${runId}:${seq}`) for crash-retry deduplication
- Remove queued approval deliveries for a turn when committing cancellation (`markCancelled` / terminal state) so `flushDeliveries` never retries or blocks on an obsolete approval
- Thread the publishing `harnessId` through `ensureSubscribed`, `applyEvent`, and `applyEventLocked` (including synchronous subscription replay) and verify it matches the turn's routed harness
- Reject a second distinct `approval-requested` event while a turn already has a `pendingApproval`
- Derive `createStateBackendStore` lock identity from the canonical shared storage (`.git` common dir across linked worktrees, resolved via `realpathSync.native`) and the state ref (`refs/heads/<branch>` or `refs/notes/<ref>`), unwrapping `TwoLayerBackend`
- Clear ambient `SQUAD_BACKEND_URL`, `SQUAD_BACKEND_TOKEN`, and `SQUAD_EXPERIMENTAL_BACKEND` before applying explicit test environment values in `McpStdioClient`

Refs #2239, #2253

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639

---------

Co-authored-by: Copilot <Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
tamirdresher added a commit that referenced this pull request Oct 22, 2026
…umentation [4/4] (#2254)

* docs(squad-2.0): consolidate multi-client and backend docs across 7 hosts (Layer 4)

Split from #2239 (Layer 4 of 4):
- Canonicalize @bradygaster/squad-sdk/client across architecture, overview, quickstart, and SDK docs
- Add Experimental Preview / Bring Your Own Server callouts for @bradygaster/squad-sdk/backend and document opt-in --experimental-backend / SQUAD_EXPERIMENTAL_BACKEND=1 MCP tools
- Update all 5-host lists to all 7 hosts (copilot, claude, kiro, opencode, cursor, codex, antigravity) and align generated-file tables with Layer 1 projections
- Consolidate architecture and multi-client docs into published Astro pages and align v0.2 specs

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9

* docs(squad-2.0): reflect audited behavior (Codex TOML agent, .gitignore lines, backend opt-in and harness caveats, https-only durable-http)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841

* docs(squad-2.0): address #2254 review threads, prepare 2.0.0 release notes & pack smoke test

- Clarify in reference/sdk.md, reference/config.md, and reference/cli.md that createSquadBackend / DurableHttpSquadBackend require explicit baseUrl (and optional token), while automatic SQUAD_BACKEND_URL / SQUAD_BACKEND_TOKEN lookup applies only to squad state-mcp when experimental backend tools are enabled
- Use canonical BACKEND_CAPABILITIES tokens (cursor-reconnect, approvals, cancel-run, typed-content-parts) in durable-backend-and-custom-harness.md
- Give each turn a distinct approvalId and track (runId, seq) per conversation and approvalId in DemoHarnessAdapter
- Update .changeset/squad-2-0-multi-host-clients.md with major bumps for @bradygaster/squad, @bradygaster/squad-sdk, and @bradygaster/squad-cli and release-notes summary
- Add v2.0.0 release notes to whatsnew.md, Upgrading to Squad 2.0 section to scenarios/upgrading.md and get-started/migration.md, and host capability matrix / Phase 2 limitations to architecture and multi-client docs
- Add test/squad-20-pack-smoke.test.ts for npm pack clean-install and v1.1.0 -> 2.0 upgrade/rollback verification

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9

---------

Co-authored-by: Copilot <Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants